/*
 * @Author: Shane
 * @Date: 2022-04-14 16:58:12
 * @LastEditTime: 2022-09-17 15:10:38
 * @LastEditors: Shane
 * @Description: 
 * @FilePath: /app-framework/common_widgets/lib/countdown_widget.dart
 */

import 'dart:async';

import 'package:flutter/cupertino.dart';

class CountDownController {
  final streamController = StreamController<int>();
  Timer? timer;
  // CountDownController();
  void dispose() {
    if (timer?.isActive == true) {
      timer?.cancel();
    }
    timer = null;
    streamController.sink.close();
    streamController.close();
  }
}

/// 获取验证码

typedef CountDownWidgetBuilder = Widget Function(
    BuildContext context, int tick);

class CustomCountDown extends StatefulWidget {
  final CountDownWidgetBuilder startChild; //开始的 widget
  final CountDownWidgetBuilder endChild; //结束的 widget
  final CountDownWidgetBuilder processChild; //进行中的 widget
  final CountDownWidgetBuilder? disableChild;
  final bool? enable; //是否允许开始
  final int count; //总时间，默认60
  final bool Function()? checkOnTap; // 是否允许点击
  final bool? autoStart; // 是否自动开始倒计时
  final Function()? endCallback;
  CountDownController? controller;

  CustomCountDown({
    required this.startChild,
    required this.endChild,
    required this.processChild,
    this.disableChild,
    this.count = 60,
    this.checkOnTap,
    this.enable = true,
    this.autoStart = false,
    this.endCallback,
    this.controller,
  }) {
    controller ??= CountDownController();
  }

  @override
  _CustomCountDownState createState() => _CustomCountDownState();
}

class _CustomCountDownState extends State<CustomCountDown> {
  @override
  void initState() {
    // widget.controller ??= CountDownController();

    if (widget.autoStart == true) {
      WidgetsBinding.instance.addPostFrameCallback((timeStamp) => _start());
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: widget.controller?.streamController.stream,
      initialData: 0,
      builder: (context, snapshot) => _buildWidget(context, snapshot),
    );
  }

  Widget _buildWidget(BuildContext context, AsyncSnapshot<int> snapshot) {
    int? tick = snapshot.data ?? 0;
    if (tick > 0 && tick < widget.count) {
      return widget.processChild.call(context, widget.count - tick);
    }
    if (widget.enable != true) {
      return widget.disableChild?.call(context, tick) ??
          widget.startChild.call(context, tick);
    }
    if (tick >= widget.count) {
      return GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTap: _onTop,
          child: widget.endChild.call(context, tick));
    }
    var widgetStart = widget.startChild.call(context, tick);
    return GestureDetector(
        behavior: HitTestBehavior.translucent,
        onTap: _onTop,
        child: widgetStart);
  }

  _onTop() {
    bool checkOnTop = (widget.checkOnTap?.call()) ?? true;
    if (!checkOnTop) return;
    _start();
  }

  void _start() {
    if (widget.controller?.timer != null &&
        widget.controller?.timer?.isActive == true) {
      widget.controller?.timer = null;
    }
    widget.controller?.timer ??=
        Timer.periodic(const Duration(seconds: 1), (timer) {
      var tick = timer.tick;
      if (widget.controller?.streamController.isClosed == false) {
        widget.controller?.streamController.sink.add(tick);
      }
      if (tick >= widget.count) {
        if (widget.endCallback != null) {
          widget.endCallback!.call();
        }

        timer.cancel();
        widget.controller?.timer = null;
      }
    });
  }

  @override
  void dispose() {
    widget.controller?.dispose();
    super.dispose();
  }
}

typedef CustomDeadlineBuilder = Widget Function(
    BuildContext context, Duration duration);

const _defaultIntervalTime = Duration(seconds: 1);

/// 计时器
class CustomDeadlineWidget extends StatefulWidget {
  final CustomDeadlineBuilder child; // 计时器的widget构造器
  final DateTime deadlineTime; // 倒计时目标时间
  final Duration intervalTime; // 倒计时的计时间隔

  const CustomDeadlineWidget(
      {Key? key,
      required this.child,
      required this.deadlineTime,
      this.intervalTime = _defaultIntervalTime})
      : super(key: key);

  @override
  _CustomDeadlineWidgetState createState() => _CustomDeadlineWidgetState();
}

class _CustomDeadlineWidgetState extends State<CustomDeadlineWidget> {
  Duration _duration = Duration();
  Timer? _timer;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _timer = Timer.periodic(widget.intervalTime, (timer) {
        _duration = Duration(
            milliseconds: widget.deadlineTime.millisecondsSinceEpoch -
                DateTime.now().millisecondsSinceEpoch);
        setState(() {});
      });
    });
    super.initState();
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child.call(context, _duration);
  }
}
